#include "StdAfx.h"
#include "XchangeKey.h"
#include "cap_key.h"
#pragma comment(lib, "cap_key.lib")

#include "Config.h"
#include "SeqInput.h"

namespace KeyAss 
{
	//--------------------------------------------------------------------------
	class HookKeyClass : public KeyHook
	{
		friend class XchangeKey;
		XchangeKey* _key;
		BYTE kbs[256];

		struct char2
		{
			char c;
			char c2;
			void SetEmpty(){c = c2 = 0;}
			bool IsEmpty(){return c == 0 && c2 == 0;}
		};
		char2 _ch;

		bool IsFinishKey(DWORD vk)
		{
			return (vk == VK_SPACE) || (vk == VK_RETURN) || (vk == VK_SEMCOLON);
		}

		int _lastIsShift;

		virtual void OnEvent(int nCode,WPARAM w, LPARAM l)
		{
			if(nCode < 0) return;
			KBDLLHOOKSTRUCT* pSt = (KBDLLHOOKSTRUCT*)l;
			if(pSt->dwExtraInfo == (ULONG_PTR)_key)
				return;

			//post key-string
			if(w == WM_KEYDOWN || w == WM_SYSKEYDOWN)
			{
				//control pause/resume
				if(pSt->vkCode == VK_RSHIFT){
					if(_lastIsShift == 1){
						_key->AppPauseResume();
						_lastIsShift = 0;
					}else{
						_lastIsShift++;
					}
				}else{
					_lastIsShift = 0;
				}
			}
			if(_key->Paused()) return;

			//transfer input:
			if(w == WM_KEYDOWN || w == WM_SYSKEYDOWN)
			{
				if(IsFinishKey(pSt->vkCode)) return;
				PostMessageA(_key->_hwnd, (UINT)w, pSt->vkCode, 0);
				return;
			}
			//check input(key-string):
			if(IsFinishKey(pSt->vkCode))
			{
				kbs[VK_SHIFT] = _key->GetShift();
				kbs[VK_CAPITAL] = _key->GetCap();

				if( 0 == ToAscii(pSt->vkCode, pSt->scanCode, kbs, (LPWORD)&_ch, 0)){
					_ch.SetEmpty();
				}
				_key->FinishInput(pSt->vkCode, _ch.c);
			}
		}

	public:
		HookKeyClass(XchangeKey* key)
		{
			_key = key;
			_lastIsShift = 0;
			memset(kbs, 0, 256);
		}
	};

	//--------------------------------------------------------------------------

	//--------------------------------------------------------------
	XchangeKey::XchangeKey(SetText st, GetText gt, PauseResume pr, HWND hwnd)
	{
		_hwnd = hwnd;
		_SetTextFunc = st;
		_GetTextFunc = gt;
		_PauseFunc = pr;
	}

	BYTE XchangeKey::GetShift()
	{
		SHORT shft = GetAsyncKeyState(VK_SHIFT);
		return (BYTE)(shft >> 8);
	}

	BYTE XchangeKey::GetCap()
	{
		SHORT cptl = GetKeyState(VK_CAPITAL);
		return (BYTE)(cptl);	
	}

	XchangeKey::~XchangeKey(void)
	{
	}

	void XchangeKey::UISet(const std::string& str)
	{
		if(_SetTextFunc) _SetTextFunc(str);
	}

	const std::string& XchangeKey::UIGet()
	{
		if(!_GetTextFunc) return empty;
		return _GetTextFunc();
	}

	void XchangeKey::AppPauseResume()
	{
		if(_PauseFunc) _PauseFunc();
	}

	void XchangeKey::ReloadCfg()
	{
		Config::get().Load();
	}

	void XchangeKey::Start()
	{
		_pause = false;
		_pHook = new HookKeyClass(this);
		_pHook->Install(WH_KEYBOARD_LL);
		InitBuffer();
		Config::get().Load();
	}

	void XchangeKey::Stop()
	{
		_pHook->Uninstall();
	}

	void XchangeKey::InitBuffer()
	{
		
	}

	void XchangeKey::FinishInput(DWORD vk, char last)
	{
		const std::string& str = UIGet();
		UISet(empty);

		const value& full = Config::get().GetFull(str);
		if(&full == &valEmpty) return;
		if(!full.IsCtrlKey(vk)) return;

		std::string fullstring = full.GetLine();
		int remove = str.length() + 1;

		if(full.IsAppend()){
			fullstring += last;
		}

		SeqInput ks(this);
		ks.AddVK(VK_BACK, remove);
		ks.AddText(fullstring);
		ks.AddVK(VK_LEFT, full.GetCursor());
		BOOL sent = ks.Send();
		OutputDebugStringA(fullstring.c_str());
		//UISet(sent ? fullstring : "[error]");
	}

}//namespace